#pragma once

#include <cstdlib>
#include <memory.h>
#include <iostream>

using namespace std;

template <typename T>
class myStack
{
private:
	T* stack;
	int stack_size;

public:
	/*Constructor, Copy constructor, Destructor*/
	myStack(int size = 0);
	myStack(const myStack& rhs);
	~myStack();

	/*Accessor*/
	inline int GetSize(void) const{ return stack_size; }
	inline void SetSize(const int size) { stack_size = size; }
	
	/*Pop, Push, Top*/
	T Pop(void);
	void Push(const T data);
	const T& Top(void) const;
	
	/*Assginment, */
	myStack operator=(const myStack& rhs);
	void operator=(const int data);
	T* operator&();
};


template <typename T>
myStack<T>::myStack(int size):stack_size(size)
{
	stack = new T[stack_size];
	memset(stack, 0, sizeof(T) * stack_size);
}

template <typename T>
myStack<T>::myStack(const myStack<T> &rhs)
{
	stack_size = rhs.GetSize();

	stack = new T[stack_size];
	memset(stack, 0, sizeof(T) * stack_size);
	
	for (int i = 0; i < stack_size; i++)
		stack[i] = rhs.stack[i];
}

template <typename T>
myStack<T>::~myStack()
{
	delete []stack;
}

template <typename T>
T myStack<T>::Pop()
try{
	if(stack_size == 0)
		throw "Stack underflow";

	T temp = stack[--stack_size];
	
	T* tempArr = new T[stack_size];
	memset(tempArr, 0, sizeof(T) * stack_size);
	memcpy(tempArr, stack, stack_size);

	delete []stack;
	stack = new T[stack_size];
	memset(stack, 0, sizeof(T) * stack_size);
	memcpy(stack, tempArr, stack_size);

	delete []tempArr;

	return temp;
}
catch(char* errMessage)
{
	cerr << errMessage << endl;
	return -1;
}

template <typename T>
void myStack<T>::Push(const T data)
{
	++stack_size;

	T* tempArr = new T[stack_size];
	memset(tempArr, 0, sizeof(T) * stack_size);
	if(stack_size != 1)
	{
		memcpy(tempArr, stack, sizeof(T) * (stack_size-1));
		delete []stack;
	}
	tempArr[stack_size-1] = data;
	
	stack = new T[stack_size];
	memset(stack, 0, sizeof(T) * stack_size);
	memcpy(stack, tempArr, sizeof(T) * stack_size);

	delete []tempArr;
}

template <typename T>
myStack<T> myStack<T>::operator =(const myStack<T> &rhs)
{
	myStack temp(rhs);

	return temp;
}

template <typename T>
void myStack<T>::operator =(const int data)
{
	Push(data);
}

template <typename T>
T* myStack<T>::operator&()
{
	return stack;
}

template <typename T>
const T& myStack<T>::Top() const
{
	if ( stack_size == 0)
		throw "underflow";

	return stack[stack_size-1];
}
